import matplotlib.pyplot as plt
import numpy as np
import pandas as pd


def load_data():
    # 数据加载
    data = pd.read_table('iris.data', sep=',', header=None)  # DataFrame是一种表格型数据结构
    # 数据标签转换
    data.loc[data[4] == 'Iris-setosa', 4] = 0  # .loc使用column名和index名进行定位  .iloc用index索引进行定位
    data.loc[data[4] == 'Iris-versicolor', 4] = 1
    data.loc[data[4] == 'Iris-virginica', 4] = 2
    # 构建训练集，测试集
    train_data, test_data = shuffle_dataset(data.values, ratioTest=0.2)  # .values：对应的二维NumPy值数组。 将dataframe转为numpy数组

    return train_data, test_data


def shuffle_dataset(data, ratioTest):
    """Shuffle the training data set randomly"""
    # 乱序
    seed = 2140280  # np.random.randint(0, 10)
    np.random.seed(seed)
    np.random.shuffle(data)
    # 拆分成测试集和验证集 五折交叉验证
    test_data = data[:int(150 * ratioTest)]
    train_data = data[int(150 * ratioTest):]

    return train_data, test_data


def gaussian_pdf(x, xi, sigma):
    """概率密度函数（Probability density function, pdf）"""
    prob = 1 / np.sqrt(2 * np.pi) / sigma * np.exp(-sum((x - xi) ** 2) / 2 / sigma ** 2)
    return prob


def Parzen_Window(x, data, h):
    """Parzen window密度估计"""
    px = [gaussian_pdf(x, xi, sigma=h) for xi in data]
    return np.mean(np.array(px), axis=0)


def classifier(test, data, h):
    px = np.zeros(3)
    acc_num = 0
    for j in range(len(test)):
        for i in range(len(px)):
            xi = [x[:4] for x in filter(lambda x: x[4] == i, data)]
            px[i] = Parzen_Window(test[j, :4], xi, h)

        if np.argmax(px) == test[j, 4]:
            acc_num += 1

    accuracy = acc_num / len(test)

    return accuracy


if __name__ == '__main__':
    # 数据预处理，制作数据集与标签
    train_data, test_data = load_data()

    h = np.arange(0.1, 5, 0.02)
    accuracy = np.zeros(len(h))

    for i in range(len(h)):
        accuracy[i] = classifier(test_data, train_data, h[i])

    plt.plot(h, accuracy)
    plt.show()
